#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
from matplotlib import pyplot as plt
from pylab import mpl

from web.util.dto_util import DtoUtil
from web.manager.log_manager import LogManager
from web.service.base_service import BaseService
from web.config.commodity_future_date_contract_data_config import CommodityFutureDateContractDataConfig
from web.config.create_date_contract_picture_config import CreateDateContractPictureConfig
from web.util.math_util import MathUtil

Logger = LogManager.get_logger(__name__)

"""
CommodityFutureDateContractData的service类
"""


class CommodityFutureDateContractDataService(BaseService):

    def save_commodity_future_date_contract_data_list_for_my_quant(self, commodity_future_date_contract_data_list,
                                                                   name):
        """
        保存CommodityFutureDateContractData类型对象列表（来自掘金量化api的数据）
        """

        Logger.info('保存CommodityFutureDateContractData类型对象列表（来自掘金量化api的数据）')

        for commodity_future_date_contract_data in commodity_future_date_contract_data_list:
            commodity_future_date_contract_data = DtoUtil.commodity_future_date_contract_data_dto_to_commodity_future_date_contract_data(
                commodity_future_date_contract_data)
            if isinstance(commodity_future_date_contract_data.close_price, str) or isinstance(
                    commodity_future_date_contract_data.highest_price, str) or isinstance(
                commodity_future_date_contract_data.open_price, str) or isinstance(
                commodity_future_date_contract_data.lowest_price, str) or isinstance(
                commodity_future_date_contract_data.volume, str) or isinstance(
                commodity_future_date_contract_data.turnover, str) or isinstance(
                commodity_future_date_contract_data.open_interest, str):
                Logger.warn('期货[%s]在交易日[%s]没有数据', commodity_future_date_contract_data.code,
                            commodity_future_date_contract_data.transaction_date.strftime('%Y-%m-%d %H:%M:%S'))
                continue
            else:
                # commodity_future_date_contract_data.transaction_date = DatetimeUtil.str_to_datetime(
                #     EastMoneyConfig.Download_Contract_Transaction_Date, DatetimeFormat.Date_Format)

                filter_dict = {'code': commodity_future_date_contract_data.code,
                               'transaction_date': commodity_future_date_contract_data.transaction_date}
                commodity_future_date_data_list = self.commodity_future_date_contract_data_dao.find_list(filter_dict,
                                                                                                         dict(), list())
                if commodity_future_date_data_list is None or len(
                        commodity_future_date_data_list) == 0:
                    commodity_future_date_contract_data.name = name
                    self.commodity_future_date_contract_data_dao.save(commodity_future_date_contract_data)
                else:
                    Logger.debug('期货[%s]在交易日[%s]已经有数据了，不再插入数据',
                                 commodity_future_date_contract_data.code,
                                 commodity_future_date_contract_data.transaction_date.strftime('%Y-%m-%d %H:%M:%S'))

    def save_commodity_future_date_data_list_for_tianqin(self, commodity_future_date_contract_data_list):
        """
        保存CommodityFutureDateContractData类型对象列表
        """

        Logger.info('保存CommodityFutureDateContractData类型对象列表')

        for commodity_future_date_contract_data in commodity_future_date_contract_data_list:
            if (np.isnan(commodity_future_date_contract_data.close_price) or np.isnan(
                    commodity_future_date_contract_data.highest_price) or
                    np.isnan(commodity_future_date_contract_data.open_price) or np.isnan(
                        commodity_future_date_contract_data.lowest_price) or
                    np.isnan(commodity_future_date_contract_data.turnover) or np.isnan(
                        commodity_future_date_contract_data.open_interest)):
                Logger.debug('期货[%s]在交易日[%s]没有数据', commodity_future_date_contract_data.code,
                             commodity_future_date_contract_data.transaction_date.strftime('%Y-%m-%d %H:%M:%S'))
                continue
            else:
                filter_dict = {'code': commodity_future_date_contract_data.code,
                               'transaction_date': commodity_future_date_contract_data.transaction_date}
                _commodity_future_date_contract_data_list = self.commodity_future_date_contract_data_dao.find_list(
                    filter_dict,
                    dict(), list())
                if _commodity_future_date_contract_data_list == None or len(
                        _commodity_future_date_contract_data_list) == 0:
                    self.commodity_future_date_contract_data_dao.save(commodity_future_date_contract_data)
                else:
                    Logger.debug('期货[%s]在交易日[%s]已经有数据了，不在插入数据',
                                 commodity_future_date_contract_data.code,
                                 commodity_future_date_contract_data.transaction_date.strftime('%Y-%m-%d %H:%M:%S'))

    ########################################### 全量计算数据 ########################################

    def write_date_basic_data(self):
        """
        计算日线级别全部last_close_price、rising_and_falling_amount和price_change字段
        """

        Logger.info("计算日线级别全部last_close_price、rising_and_falling_amount和price_change字段")

        self.commodity_future_date_contract_data_dao.write_date_basic_data()

    def write_date_all_ma(self):
        """
        计算日线级别全部MA数据
        """

        Logger.info("计算日线级别全部MA数据")

        self.commodity_future_date_contract_data_dao.write_date_all_ma()

    def write_date_all_macd(self):
        """
        计算日线级别全部MACD数据
        """

        Logger.info("计算日线级别全部MACD数据")

        self.commodity_future_date_contract_data_dao.write_date_all_macd()

    def write_date_all_kd(self):
        """
        计算日线级别全部KD数据
        """

        Logger.info("计算日线级别全部KD数据")

        self.commodity_future_date_contract_data_dao.write_date_all_kd()

    def write_date_all_boll(self):
        """
        计算日线级别全部boll数据
        """

        Logger.info("计算日线级别全部boll数据")

        self.commodity_future_date_contract_data_dao.write_date_all_boll()

    def write_date_all_hei_kin_ashi(self):
        """
        计算日线级别全部hei_kin_ashi数据
        """

        Logger.info("计算日线级别全部hei_kin_ashi数据")

        self.commodity_future_date_contract_data_dao.write_date_all_hei_kin_ashi()

    def write_date_all_bias(self):
        """
        计算日线级别全部bias数据
        """

        Logger.info("计算日线级别全部bias数据")

        self.commodity_future_date_contract_data_dao.write_date_all_bias()

    def write_date_all_variance(self):
        """
        计算日线级别全部variance数据
        """

        Logger.info("计算日线级别全部variance数据")

        self.commodity_future_date_contract_data_dao.write_date_all_variance()

    def write_date_unite_relative_price_index(self):
        """
        计算日线级别全部unite_relative_price_index数据
        """

        Logger.info("计算日线级别全部unite_relative_price_index数据")

        self.commodity_future_date_contract_data_dao.write_date_unite_relative_price_index()

    ########################################### 增量计算数据 ########################################

    def write_date_contract_basic_data_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的last_close_price、rising_and_falling_amount和price_change字段
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的last_close_price、rising_and_falling_amount和price_change字段",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Basic_Data_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_contract_basic_data_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Basic_Data_By_Date)

    def write_date_contract_unite_relative_price_index_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的unite_relative_price_index数据
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的unite_relative_price_index数据",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Unite_Relative_Price_Index_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_unite_relative_price_index_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Unite_Relative_Price_Index_By_Date)

    def write_date_contract_ma_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的MA数据
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的MA数据",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Ma_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_contract_ma_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Ma_By_Date)

    def write_date_contract_macd_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的MACD数据
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的MACD数据",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Macd_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_contract_macd_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Macd_By_Date)

    def write_date_contract_kd_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的KD数据
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的KD数据",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Kd_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_contract_kd_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Kd_By_Date)

    def write_date_contract_boll_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的boll数据
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的boll数据",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Boll_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_contract_boll_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Boll_By_Date)

    def write_date_contract_hei_kin_ashi_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的hei kin ashi数据
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的hei kin ashi数据",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Hei_Kin_Ashi_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_contract_hei_kin_ashi_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Hei_Kin_Ashi_By_Date)

    def write_date_contract_variance_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的variance数据
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的variance数据",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Variance_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_contract_variance_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Hei_Kin_Ashi_By_Date)

    def write_date_contract_bias_by_date(self):
        """
        根据日期，计算日线级别某一个交易日的BOLL数据
        """

        Logger.info("根据日期，计算日线级别交易日[%s]的BIAS数据",
                    CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Bias_By_Date)

        self.commodity_future_date_contract_data_dao.write_date_contract_bias_by_date(
            CommodityFutureDateContractDataConfig.Commodity_Future_Date_Contract_Data_Bias_By_Date)

    ########################################### 创建图片 ########################################
    def create_different_contract_compare_picture(self):
        """
        查询某一种具体合约，在一定时间范围内的记录，并按日期升序排列
        """

        Logger.info("创建图片：同一品种多个不同合约的比较图")

        distinct_code_tuple = self.commodity_future_date_contract_data_dao.distinct_code_between_transaction_date_like_code(
            CreateDateContractPictureConfig.Different_Contract_Compare_Prefix_Code,
            CreateDateContractPictureConfig.Different_Contract_Compare_Begin_Date,
            CreateDateContractPictureConfig.Different_Contract_Compare_End_Date)

        # 创建折线图
        # 创建一个新的图表
        fig, ax = plt.subplots(figsize=(18, 8))

        # 关闭交互模式
        plt.ioff()

        mpl.rcParams["font.sans-serif"] = ["SimHei"]

        # 具体合约的数据
        for code_tuple in distinct_code_tuple:
            commodity_future_date_contract_data_list = self.commodity_future_date_contract_data_dao.find_by_code_between_transaction_date_order_by_transaction_date_asc(
                code_tuple[0], CreateDateContractPictureConfig.Different_Contract_Compare_Begin_Date,
                CreateDateContractPictureConfig.Different_Contract_Compare_End_Date)

            close_price_list = list()
            transaction_date_list = list()
            for commodity_future_date_contract_data in commodity_future_date_contract_data_list:
                close_price_list.append(commodity_future_date_contract_data[7])
                transaction_date_list.append(commodity_future_date_contract_data[2])

            # 归一化
            # close_price_list = MathUtil.normalize(close_price_list)[0]
            ax.plot(transaction_date_list, close_price_list, label=code_tuple[0] + ' 收盘价（具体合约）', linewidth=0.5,
                    marker='o', color=MathUtil.generate_random_color())

        # 主力连续合约的数据
        commodity_future_date_data_list = self.commodity_future_date_data_dao.find_by_code_between_transaction_date_order_by_transaction_date_asc(
            CreateDateContractPictureConfig.Different_Contract_Compare_Main_Code,
            CreateDateContractPictureConfig.Different_Contract_Compare_Begin_Date,
            CreateDateContractPictureConfig.Different_Contract_Compare_End_Date)

        _close_price_list = list()
        _transaction_date_list = list()
        for commodity_future_date_data in commodity_future_date_data_list:
            _close_price_list.append(commodity_future_date_data[7])
            _transaction_date_list.append(commodity_future_date_data[2])

        # 归一化
        # _close_price_list = MathUtil.normalize(_close_price_list)[0]
        ax.plot(_transaction_date_list, _close_price_list,
                label=CreateDateContractPictureConfig.Different_Contract_Compare_Main_Code + ' 收盘价（主力合约）',
                linewidth=0.5,
                marker='*', color='black')

        plt.legend()
        plt.title('同一品种多个不同合约的比较图')
        plt.xlabel('时间')
        plt.ylabel('收盘价（归一化后）')

        # 分辨率
        plt.rcParams['savefig.dpi'] = 300

        # 显示图例
        # plt.legend()

        # 保存图表
        plt.savefig(CreateDateContractPictureConfig.Different_Contract_Compare_Picture_Save_Path)

        # 显示图表
        # plt.show()

        # 关闭图表
        plt.close()
